package io.geekidea.boot.system.controller;

import io.geekidea.boot.auth.annotation.Permission;
import io.geekidea.boot.framework.page.Paging;
import io.geekidea.boot.framework.response.ApiResult;
import io.geekidea.boot.system.dto.ResourceDto;
import io.geekidea.boot.system.query.ResourceQuery;
import io.geekidea.boot.system.service.ResourceService;
import io.geekidea.boot.system.vo.ResourceVo;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.geekidea.boot.framework.util.TokenUtils;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.util.UriUtils;

import javax.validation.Valid;
import java.nio.file.Path;
import java.util.HashMap;
import java.io.InputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.net.URLConnection;

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * 资源管理 控制器
 */
@RestController
@Tag(name = "资源管理")
@RequestMapping("/admin/resource")
public class ResourceController {

    private static final Logger logger = LoggerFactory.getLogger(ResourceController.class);

    @Autowired
    private ResourceService resourceService;

    @PostMapping("/addResource")
    @Operation(summary = "添加资源")
    @Permission("sys:resource:add")
    public ApiResult<Map<String, Object>> addResource(@RequestBody ResourceDto dto) {
        logger.info("Request to add resource: {}", dto);
        // 新增记录，返回包含雪花算法生成id的对象
        ResourceVo resourceVo = resourceService.addResource(dto);
        // 为确保字段完整，再次查询数据（可选）
        resourceVo = resourceService.getResourceById(resourceVo.getId());
        // 构造返回Map，确保id为字符串类型
        Map<String, Object> result = new HashMap<>();
        result.put("id", resourceVo.getId() == null ? null : String.valueOf(resourceVo.getId()));
        result.put("name", resourceVo.getName());
        result.put("version", resourceVo.getVersion());
        result.put("resourceTypeCode", resourceVo.getResourceTypeCode());
        result.put("grade", resourceVo.getGrade());
        result.put("className", resourceVo.getClassName());
        result.put("remark", resourceVo.getRemark());
        result.put("createTime", resourceVo.getCreateTime());
        result.put("fileName", resourceVo.getFileName());
        result.put("filePath", resourceVo.getFilePath());
        result.put("fileSize", resourceVo.getFileSize());
        logger.info("Resource added with ID: {}", result.get("id"));
        return ApiResult.success(result);
    }

    @PostMapping("/updateResource")
    @Operation(summary = "修改资源")
    @Permission("sys:resource:update")
    public ApiResult<Boolean> updateResource(@RequestBody ResourceDto dto) {
        logger.info("Request to update resource: {}", dto);
        boolean result = resourceService.updateResource(dto);
        logger.info("Resource updated: {}", result);
        return ApiResult.success(result);
    }

    @PostMapping("/deleteResource/{id}")
    @Operation(summary = "删除资源")
    @Permission("sys:resource:delete")
    public ApiResult<Boolean> deleteResource(@PathVariable Long id) {
        logger.info("Request to delete resource with id: {}", id);
        try {
            boolean result = resourceService.deleteResource(id);
            logger.info("Resource deleted: {}", result);
            return ApiResult.success(result);
        } catch (Exception e) {
            logger.error("Failed to delete resource: {}", id, e);
            return ApiResult.fail("删除失败：" + e.getMessage());
        }
    }

    @PostMapping("/deletePhysicalFile/{id}")
    @Operation(summary = "删除物理资源")
    public ApiResult<Boolean> deletePhysicalFile(@PathVariable Long id) {
        logger.info("Request to delete resource with id: {}", id);
        try {
            boolean result = resourceService.deletePhysicalFile(id);
            logger.info("Resource deleted: {}", result);
            return ApiResult.success(result);
        } catch (Exception e) {
            logger.error("Failed to delete resource: {}", id, e);
            return ApiResult.fail("删除失败：" + e.getMessage());
        }
    }

    @PostMapping("/getResource/{id}")
    @Operation(summary = "获取资源详情")
    public ApiResult<ResourceVo> getResourceById(@PathVariable Long id) {
        logger.info("Request to get resource by id: {}", id);
        ResourceVo resource = resourceService.getResourceById(id);
        logger.info("Resource retrieved: {}", resource);
        return ApiResult.success(resource);
    }

    @PostMapping("/getResourcePage")
    @Operation(summary = "获取资源分页列表")
    public ApiResult<ResourceVo> getResourcePage(@Valid @RequestBody ResourceQuery query) {
        logger.info("Request to get resource page with query: {}", query);
        Paging<ResourceVo> paging = resourceService.getResourcePage(query);
        logger.info("Resource page retrieved: {}", paging);
        return ApiResult.success(paging);
    }


    @PostMapping("/upload")
    @Operation(summary = "上传资源文件")
    @Permission("sys:resource:upload")
    public ApiResult<Map<String, Object>> uploadResource(@RequestParam("file") MultipartFile file, ResourceDto dto) {
        logger.info("Request to upload resource file with data: {}", dto);
        try {
            Map<String, Object> result = resourceService.uploadResource(file, dto);
            logger.info("Resource file uploaded: {}", result);
            return ApiResult.success(result);
        } catch (Exception e) {
            logger.error("Failed to upload resource file: {}", file.getOriginalFilename(), e);
            return ApiResult.fail("文件上传失败：" + e.getMessage());
        }
    }

    @GetMapping("/download/{id}")
    @Operation(summary = "下载资源文件")
    @Permission("sys:resource:download")
    public ResponseEntity<StreamingResponseBody> downloadResource(
            @PathVariable Long id,
            @RequestHeader("Authorization") String token) {
        logger.info("Request to download resource with id: {} by user: {}", id, TokenUtils.getUserId(token));
        try {
            Path filePath = resourceService.downloadResource(id);
            ResourceVo resource = resourceService.getResourceById(id);
            String fileName = resource.getFileName();

            // 双重编码文件名处理（RFC 5987 + 传统编码）
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString())
                    .replace("+", "%20");
            String rfc5987FileName = "filename*=UTF-8''" + encodedFileName;

            return ResponseEntity.ok()
                    .header(HttpHeaders.CONTENT_DISPOSITION,
                            "attachment; filename=\"" + encodedFileName + "\"; " + rfc5987FileName)
                    .contentType(MediaType.APPLICATION_OCTET_STREAM)
                    .contentLength(Files.size(filePath))
                    .header(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, must-revalidate")
                    .header(HttpHeaders.PRAGMA, "no-cache")
                    .header(HttpHeaders.EXPIRES, "0")
                    .body(outputStream -> {
                        try (InputStream inputStream = Files.newInputStream(filePath)) {
                            byte[] buffer = new byte[8192];
                            int bytesRead;
                            while ((bytesRead = inputStream.read(buffer)) != -1) {
                                outputStream.write(buffer, 0, bytesRead);
                                outputStream.flush(); // 确保每次写入后立即刷新
                            }
                            outputStream.flush();
                        } catch (IOException e) {
                            logger.error("文件下载失败，ID: {}, 路径: {}, 错误信息: {}", id, filePath, e.getMessage());
                            throw new ResponseStatusException(
                                    HttpStatus.INTERNAL_SERVER_ERROR,
                                    "文件下载失败: " + e.getMessage(),
                                    e);
                        }
                    });
        } catch (Exception e) {
            logger.error("文件下载异常，ID: {}", id, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
                    .body(outputStream -> {
                        outputStream.write(("文件下载失败: " + e.getMessage()).getBytes(StandardCharsets.UTF_8));
                    });
        }
    }
}